﻿using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using Framework;
using UnityEngine;
using LitJson;
using System.IO.Compression;
using System.IO;
using Google.Protobuf;
using System.Text;

public class Network : MonoBehaviour
{
    private static Network _instance;
    public Socket socket;
    public Thread thread_handler;
    public NetDataBuffer netdata_buffer = new NetDataBuffer();
    public List<NetData> net_datas = new List<NetData>();
    public string ip = "192.168.50.227", port = "8080";
    public string session_id = "user001";
    public bool is_login = false;
    public int mapid = 0;
    public bool is_equ = false;

    public double ticket = 0;

    public static Network Instance
    {
        get { return _instance; }

    }

    // Use this for initialization
    void Start()
    {
        _instance = this;

        string str = "asdfasdfaasdfsadfasd";

        byte[] compressBeforeByte = Encoding.GetEncoding("UTF-8").GetBytes(str);

        byte[] des = GZipUtil.Compress(compressBeforeByte);

        byte[] s = new byte[des.Length];
        System.Array.Copy(des, 0, s, 0, des.Length);
;
        //byte[] decompress = GZipUtil.DecompressBytes(compressBeforeByte);
        byte[] des2 = GZipUtil.Decompress(s);

        string str22 = System.Text.Encoding.UTF8.GetString(des2, 0, des2.Length);


        Debug.Log("Test:" + str22);
    }

    // Update is called once per frame
    void Update()
    {
        if (is_login)
        {
            ticket += Time.deltaTime;

            if (ticket >= 3)
            {
                this.send_ping();
                ticket = 0;
            }
        }
    }

    void logBytes(byte[] datas)
    {
        string text = "";
        for (int i = 0; i < datas.Length; i++)
        {
            text += " " + string.Format("{0:X}", datas[i]);
        }

        Debug.Log("[" + text + "]");
    }

    public void Connect2Server()
    {
        socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

        IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Parse(ip), int.Parse(port));

        socket.Connect(ipEndPoint);

        if (thread_handler != null)
            thread_handler.Abort();

        thread_handler = new Thread(new ThreadStart(read_thread));
        thread_handler.IsBackground = true;
        thread_handler.Start();

        StopCoroutine(actionProcessNetData());

        StartCoroutine(actionProcessNetData());
    }

    bool isRecording = false;

    void OnGUI()
    {

        GUI.Label(new Rect(10, 100, 100, 30), "服务器:");
        ip = GUI.TextField(new Rect(50, 100, 100, 30), ip);
        port = GUI.TextField(new Rect(160, 100, 40, 30), port);
        GUI.Label(new Rect(10, 140, 100, 30), "手机:");
        session_id = GUI.TextField(new Rect(50, 140, 100, 30), session_id);

        string content = "说明\r\n\r\n";
        content += "1.输入IP地址和端口，然后点击\"连接\"按钮\r\n2.默认鉴权账号(123456)点击\"登陆\"或者输入access_token，点击\"token登陆\"\r\n";

        GUIStyle fontStyle = new GUIStyle();
        fontStyle.normal.background = null;    //设置背景填充
        fontStyle.normal.textColor = new Color(0, 1, 0);   //设置字体颜色
        fontStyle.fontSize = 15;       //字体大小
        fontStyle.wordWrap = true;

        GUI.Label(new Rect(400, 100, 350, 600), content, fontStyle);


        if (socket == null || !socket.Connected)
        {
            if (GUI.Button(new Rect(220, 100, 100, 30), "连接"))
            {
                mapid = 0;
                is_login = false;

                Connect2Server();
            }
        }
        else
        {
            if (GUI.Button(new Rect(220, 100, 100, 30), "关闭"))
            {
                StopCoroutine(actionProcessNetData());

                thread_handler.Abort();
                thread_handler = null;

                net_datas.Clear();
                netdata_buffer = new NetDataBuffer();
                socket.Close();
                socket = null;
                is_login = false;
                mapid = 0;
                is_equ = false;
            }

            if (GUI.Button(new Rect(120, 200, 100, 30), "token登陆"))
            {
                send_login_by_token(session_id);

            }

            if (GUI.Button(new Rect(240, 200, 100, 30), "心跳包(5s)"))
            {
                send_ping();
            }

            if (is_login)
            {
                if (GUI.Button(new Rect(120, 200, 100, 30), "登出"))
                {
                    send_logout();
                }

                if (GUI.Button(new Rect(50, 250, 100, 30), "移动"))
                {
                    send_move(100, 30, 10, 1, 2, 3, 4);
                }

                if (GUI.Button(new Rect(170, 250, 100, 30), "传送地图2"))
                {
                    send_transfer(2);
                }

                if (GUI.Button(new Rect(290, 250, 100, 30), "传送地图1"))
                {
                    send_transfer(1);
                }

                if (GUI.Button(new Rect(410, 250, 100, 30), "技能攻击"))
                {
                    send_attack(1);
                }

                if (is_equ)
                {
                    if (GUI.Button(new Rect(530, 250, 100, 30), "卸下装备"))
                    {
                        send_equip(100, 0);
                    }
                }
                else
                {
                    if (GUI.Button(new Rect(530, 250, 100, 30), "穿上装备到1号位置"))
                    {
                        send_equip(100, 1);
                    }
                }

                if (GUI.Button(new Rect(50, 300, 100, 30), "聊天内容"))
                {
                    send_chat("Hello,world!");
                }

                if (GUI.Button(new Rect(170, 300, 100,30), "获取背包列表"))
                {
                    send_get_items(0);
                }

                if (GUI.Button(new Rect(290, 300, 100, 30), "移动物品"))
                {
                    send_move_item(1, 0, 2);
                }

                if (GUI.Button(new Rect(410, 300, 100, 30), "整理背包"))
                {
                    send_arrange_items(0);
                }

                if (GUI.Button(new Rect(530, 300, 100, 30), "删除物品"))
                {
                    send_del_item(2);
                }

                if (GUI.Button(new Rect(650, 300, 100, 30), "使用物品"))
                {
                    send_use_item(1);
                }

                if (GUI.Button(new Rect(790, 300, 100, 30), "增加物品"))
                {
                    send_add_item(2, 1, 1);
                }
            }
        }
    }

    void read_thread()
    {
        byte[] data = new byte[40960];

        while (true)
        {
            int receiveLength = socket.Receive(data);

            if (receiveLength > 0)
            {
                netdata_buffer.append(data, receiveLength);
                while (true)
                {
                    NetData new_data = netdata_buffer.pick();
                    if (new_data != null)
                    {
                        lock (net_datas)
                        {
                            net_datas.Add(new_data);
                        }
                    }
                    else
                    {
                        break;
                    }
                }
            }
        }
    }

    private IEnumerator actionProcessNetData()
    {
        while (true)
        {
            NetData net_data = null;
            lock (net_datas)
            {
                if (net_datas.Count > 0)
                {
                    net_data = net_datas[0];
                    net_datas.RemoveAt(0);
                }
            }

            if (net_data != null)
            {
                process(net_data);
            }
            else
            {
                yield return new WaitForSeconds(0.01f);
            }
        }
    }

    protected void process(NetData net_data)
    {
        NetDataListener listener = NetDataListenerMgr.GetListener(net_data.protocol);
        if (listener != null)
            listener(net_data);

        if (net_data.protocol == (short)CmdProto.Login)
        {
            login_resp ret_pack = new login_resp();
            ret_pack.MergeFrom(net_data.data);

            Debug.Log("登录结果:" + ret_pack.Msg + "," + ret_pack.User.ToString());

            is_login = true;
        }
        else if (net_data.protocol == (short)CmdProto.MapIn)
        {
            map_in_resp ret_pack = new map_in_resp();
            ret_pack.MergeFrom(net_data.data);

            IEnumerator<User> it = ret_pack.Users.GetEnumerator();
            while (it.MoveNext())
            {
                Debug.Log("场景角色:" + it.Current.Account);
            }

            Debug.Log("进入场景:" + ret_pack.ToString());
        }
        else if (net_data.protocol == (short)CmdProto.MapOut)
        {
            map_out_resp ret_pack = new map_out_resp();
            ret_pack.MergeFrom(net_data.data);

            Debug.Log("离开场景:" + ret_pack.ToString());
        }
        else if (net_data.protocol == (short)CmdProto.MapMove)
        {
            map_move_resp ret_pack = new map_move_resp();
            ret_pack.MergeFrom(net_data.data);

            Debug.Log("场景移动:" + ret_pack.ToString());
        }
        else if (net_data.protocol == (short)CmdProto.Attack)
        {
            attack_resp ret_pack = new attack_resp();
            ret_pack.MergeFrom(net_data.data);

            Debug.Log("技能攻击:" + ret_pack.ToString());
        }
        else if (net_data.protocol == (short)CmdProto.MapTransfer)
        {
            map_transfer_resp ret_pack = new map_transfer_resp();
            ret_pack.MergeFrom(net_data.data);

            Debug.Log("传送:" + ret_pack.ToString());
        }
        else if (net_data.protocol == (short)CmdProto.Equip)
        {
            equip_resp ret_pack = new equip_resp();
            ret_pack.MergeFrom(net_data.data);

            if (ret_pack.Pos == 0)
                is_equ = false;
            else
                is_equ = true;

            Debug.Log("装备:" + ret_pack.ToString());
        }
        else if (net_data.protocol == (short)CmdProto.UpdateStatus)
        {
            update_user_resp ret_pack = new update_user_resp();
            ret_pack.MergeFrom(net_data.data);

            Debug.Log("更新角色:" + ret_pack.ToString());
        }
        else if (net_data.protocol == (short)CmdProto.Chat)
        {
            chat_resp ret_pack = new chat_resp();
            ret_pack.MergeFrom(net_data.data);

            Debug.Log("聊天信息:" + ret_pack.ToString());
        }
        else if (net_data.protocol == (short) CmdProto.GetItems)
        {
            get_items_resp ret_pack = new get_items_resp();
            ret_pack.MergeFrom(net_data.data);

            Debug.Log("背包信息:" + ret_pack.ToString());
        }
        else if (net_data.protocol == (short)CmdProto.UpdateItems)
        {
            update_items_resp ret_pack = new update_items_resp();
            ret_pack.MergeFrom(net_data.data);

            Debug.Log("物品列表更新:" + ret_pack.ToString());
        }
        else if (net_data.protocol == (short)CmdProto.UseItem)
        {
            use_item_resp ret_pack = new use_item_resp();
            ret_pack.MergeFrom(net_data.data);

            Debug.Log("使用物品:" + ret_pack.ToString());
        }
        else if (net_data.protocol == (short)CmdProto.DelItem)
        {
            del_item_resp ret_pack = new del_item_resp();
            ret_pack.MergeFrom(net_data.data);

            Debug.Log("删除物品:" + ret_pack.ToString());
        }
        else if (net_data.protocol == (short) CmdProto.MoveItem)
        {
            update_items_resp ret_pack = new update_items_resp();
            ret_pack.MergeFrom(net_data.data);

            Debug.Log("移动物品:" + ret_pack.ToString());
         }
        else if (net_data.protocol == (short) CmdProto.AddItem)
        {
            add_item_resp ret_pack = new add_item_resp();
            ret_pack.MergeFrom(net_data.data);

            Debug.Log("添加物品:" + ret_pack.ToString());
        }
        else if (net_data.protocol == (short) CmdProto.Ping)
        {
            Debug.Log("心跳包");
        }
    }

    public void send_login_by_token(string access_token)
    {
        login_req req = new login_req { Token = access_token, Role = 2 };
        byte[] s = req.ToByteArray();
        NetData pack = new NetData((short)CmdProto.Login, s);
        socket.Send(pack.ToBytes());
    }

    public void send_logout()
    {
        logout_req req = new logout_req { };
        byte[] s = req.ToByteArray();
        NetData pack = new NetData((short)CmdProto.Logout, s);
        socket.Send(pack.ToBytes());
    }

    public void send_ping()
    {
        ping_req req = new ping_req { Ticket = 10000 };
        byte[] s = req.ToByteArray();
        NetData pack = new NetData((short)CmdProto.Ping, s);
        socket.Send(pack.ToBytes());
    }

    public void send_move(double targetx, double targety, double targetz, double quat_x, double quat_y, double quat_z, double quat_w)
    {
        map_move_req req = new map_move_req { Targetx = targetx, Targety = targety, Targetz = targetz, Quat = new Quat { X = quat_x, Y = quat_y, Z = quat_z, W = quat_w }  };
        byte[] s = req.ToByteArray();
        NetData pack = new NetData((short)CmdProto.MapMove, s);
        socket.Send(pack.ToBytes());
    }

    public void send_transfer(int mapid)
    {
        map_transfer_req req = new map_transfer_req { Targetmapid = mapid, Targetx = 200, Targety = 60, Targetz = 0 };
        byte[] s = req.ToByteArray();
        NetData pack = new NetData((short)CmdProto.MapTransfer, s);
        socket.Send(pack.ToBytes());
    }

    public void send_attack(int skillid)
    {
        attack_sub sub = new attack_sub { TargetUid = "NPC01" };

        attack_req req = new attack_req { Skillid = skillid, Targetx = 200, Targety = 60, Targetz = 0, Quat = new Quat { X = 0, Y = 0, Z = 0, W = 0 } };
        req.Subs.Add(sub);
        byte[] s = req.ToByteArray();
        NetData pack = new NetData((short)CmdProto.Attack, s);
        socket.Send(pack.ToBytes());
    }

    public void send_equip(int equ_id, int pos)
    {
        equip_req req = new equip_req { EquId = equ_id, Pos = pos };

        byte[] s = req.ToByteArray();
        NetData pack = new NetData((short)CmdProto.Equip, s);
        socket.Send(pack.ToBytes());
    }

    public void send_chat(string msg)
    {
        chat_req req = new chat_req { Msg = msg };
        byte[] s = req.ToByteArray();
        NetData pack = new NetData((short)CmdProto.Chat, s);
        socket.Send(pack.ToBytes());
    }

    public void send_get_items(int bag_type)
    {
        get_items_req req = new get_items_req { BagType = bag_type };
        byte[] s = req.ToByteArray();
        NetData pack = new NetData((short)CmdProto.GetItems, s);
        socket.Send(pack.ToBytes());
    }
    public void send_move_item(int id, int bag_type, int slot)
    {
        move_item_req req = new move_item_req { BagType = bag_type, Id = id, Slot = slot };
        byte[] s = req.ToByteArray();
        NetData pack = new NetData((short)CmdProto.MoveItem, s);
        socket.Send(pack.ToBytes());
    }
    public void send_arrange_items(int bag_type)
    {
        arrage_item_req req = new arrage_item_req { BagType = bag_type };
        byte[] s = req.ToByteArray();
        NetData pack = new NetData((short)CmdProto.ArrangeItems, s);
        socket.Send(pack.ToBytes());
    }
    public void send_del_item(int id)
    {
        del_item_req req = new del_item_req { Id = id };
        byte[] s = req.ToByteArray();
        NetData pack = new NetData((short)CmdProto.DelItem, s);
        socket.Send(pack.ToBytes());
    }

    public void send_use_item(int id)
    {
        use_item_req req = new use_item_req { Id = id };
        byte[] s = req.ToByteArray();
        NetData pack = new NetData((short)CmdProto.UseItem, s);
        socket.Send(pack.ToBytes());
    }
    
    public void send_add_item(int entry, int type, int num)
    {
        add_item_req req = new add_item_req { BagType = 0, Entry = entry, Type = type, Num = num };
        byte[] s = req.ToByteArray();
        NetData pack = new NetData((short)CmdProto.AddItem, s);
        socket.Send(pack.ToBytes());
    }
}
